package com.sxhuayuan.parking.compenent;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.StringTokenizer;

import javax.imageio.ImageIO;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ClassUtils;

import com.octo.captcha.CaptchaException;
import com.octo.captcha.component.image.backgroundgenerator.BackgroundGenerator;

public class FileReaderRandomBackgroundGenerator implements BackgroundGenerator {

	Logger log = LoggerFactory.getLogger(getClass());

	private int height = 100;
	private int width = 200;
	Random myRandom = new SecureRandom();
	private List<BufferedImage> images = new ArrayList<>();
	private String rootPath = ".";
	private String classpath = null;
	private ClassLoader classLoader = null;

	/**
	 * 传统的File读取不到jar包里的目录，只能用getResource(classpath相对路径文件名)的方式读取，没有办法获取文件列表，所以只能手动配置传入了...
	 * 
	 * @param width
	 * @param height
	 * @param rootPath
	 * @param fileNamePrefix
	 * @param count
	 */
	public FileReaderRandomBackgroundGenerator(Integer width, Integer height, String rootPath, String fileNamePrefix, int count) {
		this.width = (width != null ? width.intValue() : this.width);
		this.height = (height != null ? height.intValue() : this.height);
		if (rootPath != null) {
			this.rootPath = rootPath;
		}
		classLoader = FileReaderRandomBackgroundGenerator.class.getClassLoader();
		classpath = classLoader.getResource("").getPath();
		if (classpath.startsWith("/"))
			classpath = classpath.substring(1);
		for (int i = 0; i < count; i++) {
			String fileName = String.format(fileNamePrefix, i);
			BufferedImage image = getImage(this.rootPath + fileName);
			if (image != null) {
				this.images.add(this.images.size(), image);
			}
		}
		if (this.images.size() != 0) {
			for (int i = 0; i < this.images.size(); i++) {
				BufferedImage bufferedImage = (BufferedImage) this.images.get(i);
				this.images.set(i, tile(bufferedImage));
			}
		} else {
			throw new CaptchaException("Root path directory is valid but does not contains any image (jpg) files");
		}

	}

	protected static Map<String, File> cachedDirectories = new HashMap<>();

	// // 把所有的\换为/
	// private String parsePath(String url) {
	// String string = url.replaceAll("\\\\", "/");
	// log.debug("parsePath = {}", string);
	// return string;
	// }
	//
	// // 换取相对路径
	// private String getRelativePath(String absolutePath) {
	// String s = absolutePath.replace(classpath, "");
	// log.debug("relativePath = {}", s);
	// return s;
	// }

	// private boolean canRead(File dir) {
	// String name = getRelativePath(parsePath(dir.getAbsolutePath()));
	// log.debug("carRead name = {}", name);
	// return classLoader.getResource(name) != null;
	// }

	protected File findDirectory(String rootPath) {
		if (cachedDirectories.containsKey(rootPath)) {
			return (File) cachedDirectories.get(rootPath);
		}
		File dir = new File(rootPath);
		StringBuffer triedPath = new StringBuffer();
		appendFilePath(triedPath, dir);
		if ((!dir.canRead()) || (!dir.isDirectory())) {
			dir = new File(".", rootPath);
			appendFilePath(triedPath, dir);
			if ((!dir.canRead()) || (!dir.isDirectory())) {
				dir = new File("/", rootPath);
				appendFilePath(triedPath, dir);
				if ((!dir.canRead()) || (!dir.isDirectory())) {
					URL url = FileReaderRandomBackgroundGenerator.class.getClassLoader().getResource(rootPath);
					if (url != null) {
						dir = new File(url.getFile());
						appendFilePath(triedPath, dir);
					} else {
						url = ClassLoader.getSystemClassLoader().getResource(rootPath);
						if (url != null) {
							dir = new File(url.getFile());
							appendFilePath(triedPath, dir);
						}
					}
				}
			}
		}
		if ((!dir.canRead()) || (!dir.isDirectory())) {
			StringTokenizer token = getClasspathFromSystemProperty();
			while (token.hasMoreElements()) {
				String path = token.nextToken();
				if (!path.endsWith(".jar")) {
					dir = new File(path, rootPath);
					appendFilePath(triedPath, dir);
					if ((dir.canRead()) && (dir.isDirectory())) {
						break;
					}
				}
			}
		}
		if ((!dir.canRead()) || (!dir.isDirectory())) {
			throw new CaptchaException("All tried paths :'" + triedPath.toString() + "' is not" + " a directory or cannot be read");
		}
		cachedDirectories.put(rootPath, dir);

		return dir;
	}

	private StringTokenizer getClasspathFromSystemProperty() {
		String classpath = System.getProperty("java.class.path");
		StringTokenizer token = new StringTokenizer(classpath, File.pathSeparator);
		return token;
	}

	private void appendFilePath(StringBuffer triedPath, File dir) {
		log.debug("尝试的路径:" + dir.getAbsolutePath());
		triedPath.append(dir.getAbsolutePath());
		triedPath.append("\n");
	}

	private BufferedImage tile(BufferedImage tileImage) {
		BufferedImage image = new BufferedImage(getImageWidth(), getImageHeight(), tileImage.getType());

		Graphics2D g2 = (Graphics2D) image.getGraphics();
		int NumberX = getImageWidth() / tileImage.getWidth();
		int NumberY = getImageHeight() / tileImage.getHeight();
		for (int k = 0; k <= NumberY; k++) {
			for (int l = 0; l <= NumberX; l++) {
				g2.drawImage(tileImage, l * tileImage.getWidth(), k * tileImage.getHeight(), Math.min(tileImage.getWidth(), getImageWidth()),
						Math.min(tileImage.getHeight(), getImageHeight()), null);
			}
		}
		g2.dispose();
		return image;
	}

	private BufferedImage getImage(String path) {
		BufferedImage out = null;
		try {
			// log.debug("getImage: {}", path);
			InputStream resourceAsStream = ClassUtils.getDefaultClassLoader().getResourceAsStream(path);
			if (resourceAsStream == null)
				return null;
			out = ImageIO.read(resourceAsStream);
			return out;
		} catch (IOException e) {
			throw new CaptchaException("Unknown error during file reading ", e);
		}
	}

	public BufferedImage getBackground() {
		return this.images.get(this.myRandom.nextInt(this.images.size()));
	}

	@Override
	public int getImageHeight() {
		return this.height;
	}

	@Override
	public int getImageWidth() {
		return this.width;
	}
}
